package com.sangmo.fts.process.receivable.service;

import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.common.session.UserSession;
import com.sangmo.boot.framework.common.utils.DateUtils;
import com.sangmo.boot.framework.data.filter.PageResult;
import com.sangmo.boot.framework.data.filter.PageSearch;
import com.sangmo.boot.framework.data.filter.ValueFilter;
import com.sangmo.boot.framework.data.idm.IdentityManager;
import com.sangmo.boot.framework.plugin.dataview.crud.service.DelegateViewService;
import com.sangmo.boot.framework.plugin.dataview.crud.service.ViewService;
import com.sangmo.fts.common.utils.RandomUtils;
import com.sangmo.fts.process.inventory.model.IfLoan;
import com.sangmo.fts.process.receivable.interfaces.RpfLoanAuditRequest;
import com.sangmo.fts.process.receivable.model.RpfLoan;
import com.sangmo.fts.process.storage.interfaces.CsfLoanAuditRequest;
import com.sangmo.fts.process.storage.model.CsfLoan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;

@Service
@Transactional
public class RpfLoanService extends DelegateViewService<RpfLoan> {

    @Autowired
    private RpfLoanEntityService rpfLoanEntityService;

    @Autowired
    private IdentityManager identityManager;

    @Override
    protected ViewService<RpfLoan> getEntityService() {
        return rpfLoanEntityService;
    }

    public void accept(Long id) {
        RpfLoan loan = this.get(id);
        if (!RpfLoan.States.ACCEPTING.equals(loan.getState())) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.rpfLoan.accept.state.wrong");
        }
        loan.setState(CsfLoan.States.PENDING);
        loan.setAcceptCode(RandomUtils.generateRandomNum(10));
        this.save(loan);
    }

    public RpfLoan findByWaybillId(Long waybillId) {
        return rpfLoanEntityService.findByWaybillId(waybillId);
    }

    public void audit(Long id, RpfLoanAuditRequest request) {
        RpfLoan loan = this.get(id);
        if (!RpfLoan.States.PENDING.equals(loan.getState())) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.rpfLoan.audit.state.wrong");
        }
        loan.setAuditMind(request.getAuditMind());
        loan.setState(request.isPass()?RpfLoan.States.CONFIRMED:RpfLoan.States.REJECTED);
        loan.setIssueState(request.isPass()?RpfLoan.IssueStates.PENDING:null);
        loan.setAuditBy((Long) UserSession.getUserInterface().getId());
        loan.setAuditTime(new Date());
        this.save(loan);
    }

    public void issue(Long id) {
        RpfLoan loan = this.get(id);
        if (!RpfLoan.States.CONFIRMED.equals(loan.getState())) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.rpfLoan.audit.state.wrong");
        }
        loan.setCode(RandomUtils.generateRandomNum(10));
        loan.setIssueState(IfLoan.IssueStates.COMPLETED);
        this.save(loan);
    }

    public PageResult<RpfLoan> selection(PageSearch ps) {
        ps.getFilters().add(new ValueFilter("issueState", ValueFilter.OP_EQ, RpfLoan.IssueStates.COMPLETED));
        ps.getFilters().add(new ValueFilter("settled", ValueFilter.OP_EQ, true));
        return super.search(ps);
    }

    public void settle(Long loanId, BigDecimal amount) {
        RpfLoan loan = this.get(loanId);
        if (loan.getAmount().compareTo(amount) <= 0) {
            loan.setSettled(true);
            this.save(loan);
        }
    }
}
